package com.imagecollector.service.impl;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.imagecollector.common.constant.TaskConstant;
import com.imagecollector.domain.dto.TaskAddDTO;
import com.imagecollector.domain.dto.TaskSearchDTO;
import com.imagecollector.domain.dto.TaskUpdateDTO;
import com.imagecollector.domain.entity.*;
import com.imagecollector.domain.vo.TaskSearchVO;
import com.imagecollector.mapper.TaskMapper;
import com.imagecollector.service.IDistrictService;
import com.imagecollector.service.ITaskService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;


/**
 * <p>
 * 任务表 服务实现类
 * </p>
 *
 * @author wrf
 * @since 2024-07-31
 */
@Service
@Slf4j
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements ITaskService {
    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private TaskReceiverRecordServiceImpl taskReceiverRecordService;
    @Autowired
    private TaskSubmitRecordServiceImpl taskSubmitRecordService;
    @Autowired
    private PictureServiceImpl pictureService;
    @Autowired
    private TaskAbandonRecordServiceImpl taskAbandonRecordService;
    @Autowired
    private IDistrictService districtService;
    @Override
    public boolean createTask(TaskAddDTO taskAddDTO) {
        Task task = new Task()
                .setTitle(taskAddDTO.getTitle())
                .setDescriptions(taskAddDTO.getDescribe())
                .setRequirement(taskAddDTO.getRequirement())
                .setPicNum(taskAddDTO.getPicNum())
                .setDeadline(taskAddDTO.getDeadline())
                .setReward(taskAddDTO.getReward())
                .setIsRepeatedlyReceive(taskAddDTO.getIsRepeatedlyReceive())
                .setStatus(0);
        if (Objects.nonNull(taskAddDTO.getDistrictId())){
            task.setDistrictId(taskAddDTO.getDistrictId());
        }
        save(task);
        return true;
    }

    @Override
    public boolean publishOrRemovalTask(Integer taskId) {
        Task task = getById(taskId);
        Objects.requireNonNull(task, "任务不存在");
        if (Objects.equals(task.getStatus(), TaskConstant.TASK_STATUS_UNPUBLISHED)) {
            task.setStatus(TaskConstant.TASK_STATUS_PUBLISHED);
        }else {
            task.setStatus(TaskConstant.TASK_STATUS_UNPUBLISHED);
        }
        updateById(task);
        return true;
    }

    @Override
    public boolean updateTask(TaskUpdateDTO taskUpdateDTO) {
        Task task = getById(taskUpdateDTO.getTaskId());
        Objects.requireNonNull(task, "任务不存在");
        task.setDistrictId(taskUpdateDTO.getDistrictId())
                .setTitle(taskUpdateDTO.getTitle())
                .setDescriptions(taskUpdateDTO.getDescribe())
                .setRequirement(taskUpdateDTO.getRequirement())
                .setPicNum(taskUpdateDTO.getPicNum())
                .setReward(taskUpdateDTO.getReward())
                .setDeadline(taskUpdateDTO.getDeadline())
                .setIsRepeatedlyReceive(taskUpdateDTO.getIsRepeatedlyReceive());
        updateById(task);
        return true;
    }

    @Override
    public TaskSearchVO getTaskInfo(Integer taskId) {
        Task task = getById(taskId);
        Objects.requireNonNull(task, "任务不存在");
        String districtName = "";
        if (Objects.nonNull(task.getDistrictId())){
            districtName = districtService.getDistrictFullName(task.getDistrictId());
        }
        return new TaskSearchVO()
                .setId(task.getId())
                .setTitle(task.getTitle())
                .setDistrictId(task.getDistrictId())
                .setDistrictName(districtName)
                .setDescribe(task.getDescriptions())
                .setRequirement(task.getRequirement())
                .setPicNum(task.getPicNum())
                .setDeadline(DateUtil.formatLocalDateTime(task.getDeadline()))
                .setIsRepeatedlyReceive(task.getIsRepeatedlyReceive())
                .setStatus(task.getStatus())
                .setCreateTime(DateUtil.formatLocalDateTime(task.getDeadline()));
    }

    @Override
    @Transactional
    public boolean cancelUserReceive(Integer taskId, Integer userId) {
        TaskReceiverRecord taskReceiverRecord = taskReceiverRecordService.getByTaskId(taskId);
        Task task = getById(taskId);
        Objects.requireNonNull(taskReceiverRecord, "此用户未接取该任务");
        if (Objects.equals(taskReceiverRecord.getStatus(), TaskConstant.TASK_STATUS_RECEIVED)) {
            taskReceiverRecord.setStatus(TaskConstant.TASK_STATUS_ADMIN_ABANDONS);
            taskReceiverRecordService.updateById(taskReceiverRecord);
        }
        if (task.getIsRepeatedlyReceive() == 0){
            task.setStatus(TaskConstant.TASK_STATUS_UNPUBLISHED);
            updateById(task);
        }
        return true;
    }

    @Override
    public Page<TaskSearchVO> taskList(TaskSearchDTO taskSearchDTO) {

        LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<Task>()
                .eq(Objects.nonNull(taskSearchDTO.getTaskId()), Task::getId, taskSearchDTO.getTaskId())
                .eq(Objects.nonNull(taskSearchDTO.getDistrictId()), Task::getDistrictId, taskSearchDTO.getDistrictId())
                .eq(Objects.nonNull(taskSearchDTO.getStatus()), Task::getStatus, taskSearchDTO.getStatus())
                .eq(Objects.nonNull(taskSearchDTO.getIsRepeatedlyReceive()), Task::getIsRepeatedlyReceive, taskSearchDTO.getIsRepeatedlyReceive())
                .like(Objects.nonNull(taskSearchDTO.getTitle()), Task::getTitle, taskSearchDTO.getTitle())
                .like(Objects.nonNull(taskSearchDTO.getDescribe()), Task::getDescriptions, taskSearchDTO.getDescribe())
                .like(Objects.nonNull(taskSearchDTO.getRequirement()), Task::getRequirement, taskSearchDTO.getRequirement())
                .ge(Objects.nonNull(taskSearchDTO.getPicNum()), Task::getPicNum, taskSearchDTO.getPicNum())
                .between(Objects.nonNull(taskSearchDTO.getDeadlineStart()), Task::getDeadline, taskSearchDTO.getDeadlineStart(), taskSearchDTO.getDeadlineEnd())
                .between(Objects.nonNull(taskSearchDTO.getCreateTimeStart()), Task::getCreateTime, taskSearchDTO.getCreateTimeStart(), taskSearchDTO.getCreateTimeEnd())
                .between(Objects.nonNull(taskSearchDTO.getRewardStart()), Task::getReward, taskSearchDTO.getRewardStart(), taskSearchDTO.getRewardEnd())
                .orderByDesc(Task::getCreateTime);
        Page<Task> taskPage = page(Page.of(taskSearchDTO.getPageNo(), taskSearchDTO.getPageSize()), wrapper);
        List<TaskSearchVO> taskSearchVOS = taskPage.getRecords().stream().map(task -> new TaskSearchVO()
                .setId(task.getId())
                .setTitle(task.getTitle())
                .setDistrictId(task.getDistrictId())
                .setDistrictName(districtService.getDistrictFullName(task.getDistrictId()))
                .setDescribe(task.getDescriptions())
                .setRequirement(task.getRequirement())
                .setReward(task.getReward())
                .setPicNum(task.getPicNum())
                .setDeadline(DateUtil.formatLocalDateTime(task.getDeadline()))
                .setIsRepeatedlyReceive(task.getIsRepeatedlyReceive())
                .setStatus(task.getStatus())
                .setCreateTime(DateUtil.formatLocalDateTime(task.getCreateTime()))).collect(Collectors.toList());
        return new Page<TaskSearchVO>().setRecords(taskSearchVOS).setTotal(taskPage.getTotal());
    }

    @Override
    @Transactional
    public void scanTaskAndSetExpireStatus() {
        List<Task> expiredTask = lambdaQuery()
                .lt(Task::getDeadline, LocalDateTime.now())
                .ne(Task::getStatus, TaskConstant.TASK_STATUS_EXPIRED).list();
        expiredTask.forEach(task -> {
            task.setStatus(TaskConstant.TASK_STATUS_EXPIRED);
            updateById(task);
        });
        saveOrUpdateBatch(expiredTask);
    }
}
